package com.lechi.web.server.handle;

import com.lechi.iot.netty.utils.NettyCacheUtils;
import com.lechi.web.common.alarm.AlarmRuleStrategy;
import com.lechi.web.common.utils.spring.SpringUtils;
import com.lechi.web.constants.Constants;
import com.lechi.web.framework.util.GuavaCacheUtil;
import com.lechi.web.service.IIotAlertRecordService;
import com.lechi.web.service.IIotMonitorDataService;
import com.lechi.web.system.domain.IotAlertRecord;
import com.lechi.web.system.domain.IotMonitorDataBo;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;

import java.net.InetSocketAddress;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;

public interface BaseWeatherInboundHandle {

    Logger log = LoggerFactory.getLogger(BaseWeatherInboundHandle.class);


    String $DATADICK = "$DATADICK";


    int checkCodeArrIndex = 2;

    default boolean checkEquals(String dataRecord) {
        if (!dataRecord.contains("ED")) {
            return false;
        }
        String[] sensorDataArr = dataRecord.split(",");
        int checkNumSource = 0;
        try {
            checkNumSource = Integer.parseInt(sensorDataArr[sensorDataArr.length - checkCodeArrIndex]);
        } catch (NumberFormatException e) {
            return false;
        }
        Integer checkNum = dataRecord.substring(0, dataRecord.lastIndexOf("ED") - 5).chars().sum() % 10000;
        return Objects.equals(checkNumSource, checkNum) || Objects.equals(checkNum, checkNumSource + 44);
    }

    default void insertData(IotMonitorDataBo iotMonitorDataBo) {
        CompletableFuture.runAsync(() -> {
            SpringUtils.getBean(IIotMonitorDataService.class).batchInsert(Constants.MONITOR_DATA_TABLE + iotMonitorDataBo.getDeviceId(), List.of(iotMonitorDataBo));
        });
    }

    default String getHostName(ChannelHandlerContext ctx) {
        InetSocketAddress inetSocketAddress = (InetSocketAddress) ctx.channel().remoteAddress();
        return inetSocketAddress.getAddress().getHostAddress() + ":" + inetSocketAddress.getPort();
    }



    /**
     * Alarm rule chain.
     *
     * @param iotMonitorDataBo the iot monitor data bo
     */
    default void alarmRuleChain(IotMonitorDataBo iotMonitorDataBo) {
        String alarmRuleKey = "AlarmRule_Id_" + iotMonitorDataBo.getDeviceId() + "_" + iotMonitorDataBo.getSensorAliasId();
        List<AlarmRuleStrategy>  alarmRuleStrategyList = (List<AlarmRuleStrategy>) GuavaCacheUtil.getAlarmRuleMap().get(alarmRuleKey);
        // 告警开关必须打开，针对这个传感器的规则拿到遍历 触发
        if (alarmRuleStrategyList == null || alarmRuleStrategyList.isEmpty()) {
          //  log.info("设备：{}，传感器：{}，获取告警规则为空, 没有配置告警规则！", iotMonitorDataBo.getDeviceId(), iotMonitorDataBo.getSensorAliasId());
            return;
        }
        Set<Long> alarmSet = GuavaCacheUtil.getAlarmSensorMap().computeIfAbsent(iotMonitorDataBo.getDeviceId() + "_IF_ALARM", k -> new HashSet<>());
        String alarmRuleTypeKey = "AlarmRuleType_" + iotMonitorDataBo.getDeviceId() + "_" + iotMonitorDataBo.getSensorAliasId();
        for (AlarmRuleStrategy alarmRuleStrategy : alarmRuleStrategyList) {
            if (!Constants.TRIGGER_OPEN_STATUE.equals(alarmRuleStrategy.getStatus())) {
                log.error("设备：{}，传感器：{}，告警没用打开！", iotMonitorDataBo.getDeviceId(), iotMonitorDataBo.getSensorAliasId());
                iotMonitorDataBo.setIfAlarm(false);
                alarmSet.remove(iotMonitorDataBo.getSensorAliasId());
                NettyCacheUtils.remove(alarmRuleTypeKey);
                continue;
            }
            if (alarmRuleStrategy.ifAlarm(iotMonitorDataBo.getValue())) {
                iotMonitorDataBo.setIfAlarm(true);
                log.error("{}，告警类型：{}, 产生告警：{}", alarmRuleTypeKey, alarmRuleStrategy.getAlarmType(), iotMonitorDataBo.getValue());
                alarmSet.add(iotMonitorDataBo.getSensorAliasId());
                if (NettyCacheUtils.get(alarmRuleTypeKey, String.class) == null) {
                    addAlarmRecord(alarmRuleStrategy, iotMonitorDataBo);
                    NettyCacheUtils.put(alarmRuleTypeKey, alarmRuleStrategy.getAlarmType());
                }
            }
        };
    }

    private void addAlarmRecord(AlarmRuleStrategy alarmRuleStrategy, IotMonitorDataBo iotMonitorDataBo) {
        IotAlertRecord iotAlertRecord = new IotAlertRecord();
        iotAlertRecord.setSendFlag(0);
        BeanUtils.copyProperties(iotMonitorDataBo, iotAlertRecord);
        iotAlertRecord.setAlertName(alarmRuleStrategy.getAlarmName());
        iotAlertRecord.setTriggerValue(iotMonitorDataBo.getValue()); // 触发值可能是触发器的值也可能是上报值
        iotAlertRecord.setContent(alarmRuleStrategy.getMsgTemplate());
        iotAlertRecord.setAlertType(alarmRuleStrategy.getAlarmType());

        CompletableFuture.runAsync(() -> SpringUtils.getBean(IIotAlertRecordService.class).insertIotAlertRecord(iotAlertRecord));
    }


    default List<Long> getKeysByValue(String value) {
        List<Long> keys = new ArrayList<>();
        Map<Long, String> map = GuavaCacheUtil.getDeviceIdAndIPMap();
        for (Map.Entry<Long, String> entry : map.entrySet()) {
            if (entry.getValue().equals(value)) {
                keys.add(entry.getKey());
            }
        }
        return keys;
    }


    default Date parseStrToDate(String date) {
        try {
            return new SimpleDateFormat("yyyyMMddHHmmss").parse(date);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
}
